#ifndef _LOADER_H_
#define _LOADER_H_

#include "os_mem.h"
#include "process.h"
#include "os_queue.h"
#include "semaphores.h"
#include "os_queue.h"
#include "os_dev.h"

#define MAX_PROCESSES			512


/* @todo: move these to PD component */
#define MAX_REGS 17
#define REGSET_PC_INDEX     16  //8
#define REGSET_SP_INDEX     5   //14
#define REGSET_PSR_INDEX    6   //15
#define REGSET_R0_INDEX     8

#define PROCESS_NAME_MAX  32

typedef enum
{
	process_ready,
	process_waiting,
	process_running,
	process_dead
}process_state_t;

typedef mem_buffer_t stack_info_t;

typedef struct pcb_t
{
	mem_block_t pcb_header;
	stack_info_t *stack_ptr;		// base address of stack memory
	process_state_t  process_state;		

	uint8_t name[PROCESS_NAME_MAX];

	uint32_t regs[MAX_REGS];		// r0-r7, pc+4, r8-r12, sp, psr, lr

	struct pcb_t *prev_ready;
	struct pcb_t *next_ready;	// Next node in the ready queue

        process_list_t blocked_process;  // chain of blocked processes on same resource
	sem_t *blocked_res;		// Handle to resource on which process is blocked

	q_data_t *owned_queues;    // List of queues owned by the process 

	dev_entry_t device_list;  // List of devices opened by the process

	uint8_t process_priority;	// 0-15. 0 is highest, 15 is lowest

	uint16_t running_counter;   // unique counter incremented on every pcb alloc

}pcb_t;

#define GET_PID_FROM_PCB(pcb)  (pcb->pcb_header.block_index << 16 | pcb->running_counter)
#define GET_PID_INDEX_FROM_PCB(pcb) (pcb->pcb_header.block_index)
#define GET_PID_INDEX_FROM_PID(pid) ((pid >> 16) & 0xFFFF)
#define GET_RUNNING_COUNT_FROM_PID(pid) ((pid) & 0xFFFF)
	
void loader_init(void);
uint32_t *create_os_process(void);
bool load_program(void (*addr)(void), const uint8_t *name, uint32_t stack_size, uint8_t process_priority);
void free_process_memory(pcb_t *pcb);

void exit_process(uint32_t exit_code);
void exec_process(uint32_t process_info);

pcb_t *get_current_process(void);
uint32_t get_current_pid(void);
pcb_t *get_process(uint32_t pid);
bool is_valid_pid(uint32_t pid);
void dump_processes(void);
#endif
